package com.yesep.learn.design.behavioral.observer;

/**
 * 观察者模式（Observer Pattern），又称发布/订阅模式、模型-视图模式、源-收听者模式或从属者模式，是软件设计模式中的一种行为型模式。
 * 它定义了对象之间的一种一对多依赖关系，使得当一个对象的状态发生改变时，所有依赖于它的对象都会得到通知并被自动更新。
 * 以下是关于观察者模式的详细解析：
 * <p>
 * 一、定义与原理
 * 观察者模式的核心在于建立一种对象间的一对多依赖关系，让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时，会通知所有注册的观察者对象，并自动更新它们的状态。这种模式的关键在于解耦观察者和被观察者，使得它们可以独立变化而互不影响。
 * <p>
 * 二、结构与角色
 * 观察者模式主要包含以下几个角色：
 * <p>
 * 抽象主题（Subject）：它把所有观察者对象的引用保存到一个聚集里，每个主题都可以有任何数量的观察者。抽象主题提供一个接口，用于增加和删除观察者对象，并在内部状态改变时通知所有观察者。
 * 具体主题（Concrete Subject）：将有关状态存入具体观察者对象；在具体主题内部状态改变时，给所有登记过的观察者发出通知。
 * 抽象观察者（Observer）：为所有的具体观察者定义一个接口，在得到主题通知时更新自己。
 * 具体观察者（Concrete Observer）：实现抽象观察者角色所要求的更新接口，以便使本身的状态与主题状态协调。
 * 三、优缺点
 * 优点：
 * <p>
 * 降低耦合度：观察者和被观察者之间建立的是抽象耦合关系，符合依赖倒置原则，提高了系统的灵活性。
 * 支持广播通信：当主题对象发生变化时，可以广播通知所有观察者对象，实现了消息的自动传递。
 * 易于扩展：由于观察者和被观察者之间是松耦合的，因此可以方便地增加或删除观察者对象，而不会影响其他对象。
 * 缺点：
 * <p>
 * 可能导致系统复杂度增加：当系统中存在大量的观察者和被观察者时，可能会增加系统的复杂度，降低系统的可维护性。
 * 性能问题：如果一个被观察者有很多观察者，那么在通知所有观察者时可能会消耗较多的时间和资源，影响系统的性能。
 * 四、应用场景
 * 观察者模式在许多应用场景中都能够发挥作用，特别是在需要处理对象之间的松耦合关系、实时通知和更新的情况下。以下是一些典型的应用场景：
 * <p>
 * 发布-订阅系统：观察者模式是发布-订阅模式的核心，当发布者发布新消息或事件时，所有订阅者都会收到通知并执行相应的操作。
 * 事件处理机制：在事件驱动的编程中，观察者模式用于处理事件。当事件触发时，事件源对象会通知事件处理程序（观察者）以执行相应的操作。
 * 实时数据更新：在需要实时更新数据的应用中，观察者模式可以用于将数据源与数据消费者连接起来。当数据源的数据发生变化时，观察者可以自动获取最新的数据并进行处理。
 * 库和框架：许多编程库和框架使用观察者模式来支持插件和扩展。开发人员可以编写自定义观察者以响应库或框架中的事件或回调。
 * 消息队列系统：观察者模式可用于消息队列系统，其中生产者将消息发送到队列，而消费者作为观察者订阅队列以接收和处理消息。
 * 股票市场监测：股票市场应用程序可以使用观察者模式来监测股票价格变化，并将这些变化通知给投资者。
 * 游戏开发：在游戏中，观察者模式可用于处理各种事件，如玩家输入、碰撞检测、角色状态变化等。
 * 网络通信：在网络应用中，观察者模式可用于实现即时通信系统，其中用户之间的消息传递可以通过观察者模式来实现。
 * 五、实现示例
 * 由于篇幅限制，这里不直接给出完整的代码实现，但可以提供一个简化的实现思路：
 * <p>
 * 定义抽象主题（Subject）接口，包含增加、删除观察者和通知观察者的方法。
 * 定义抽象观察者（Observer）接口，包含一个更新方法用于在接收到通知时更新状态。
 * 实现具体主题（Concrete Subject）类，实现抽象主题接口，并在内部状态改变时调用通知方法。
 * 实现具体观察者（Concrete Observer）类，实现抽象观察者接口，定义更新方法的具体实现。
 * 通过以上步骤，可以构建出一个简单的观察者模式实现框架，并在实际应用中根据需要进行扩展和修改。
 */
public class Main {
    public static void main(String[] args) {
        SubscriptionSubject subscriptionSubject = new SubscriptionSubject();
        WechatUser wechatUser = new WechatUser("路人甲");
        EmailUser emailUser = new EmailUser("路人乙");
        subscriptionSubject.register(wechatUser);
        subscriptionSubject.register(emailUser);
        subscriptionSubject.notify("要下雨了");
        subscriptionSubject.notify("快收衣服");
    }
}
